import Timekeeper
import Configurable
import HUD
import G
import pygame
import Util
import Config

indexcheckinterval = 5
flashintervalbase = 4

class Effect(pygame.sprite.Sprite, Configurable.Configurable, Timekeeper.Timekeeper):
   runtime_vars = ('time_left',
                'last_updated',
                'target',
                'indexchecktimer',
                'flashtimer')
   
   imagepath = None
                
   __slots__ = ('duration',
                'stacks') + runtime_vars
   
   def __init__(self, duration=0.0, description="", stacks=False):
      pygame.sprite.Sprite.__init__(self)
      Configurable.Configurable.__init__(self, locals())
      if self.__class__.imagepath is not None:
         self.image, self.rect = Util.load_image(self.__class__.imagepath)
      self.time_left = self.duration
      self.indexchecktimer = 0
      self.flashtimer = 0
   
   def end(self):
      self.kill()
   
   def flashinterval(self):
      return int(flashintervalbase * (self.time_left + 1))
   
   def start(self, target):
      self.target = target
      if not self.stacks:
         for effect in G.effect_sprites.sprites():
            if isinstance(effect, self.__class__) and effect.target is self.target:
               effect.end()
               self.time_left += effect.time_left
      G.effect_sprites.add(self)
   
   def update(self):
      if self.indexchecktimer == 0:
         self.rect.topleft = (25 + 50 * G.effect_sprites.sprites().index(self),
                              Config.height - 75)
      self.indexchecktimer = (self.indexchecktimer + 1) % indexcheckinterval
      self.time_left -= self.frame()
      if self.time_left < 5.0:
         self.flashtimer += 1
         interval = self.flashinterval()
         if self.flashtimer >= interval / 2:
            self.image.set_alpha(0)
            self.flashtimer %= interval
         else:
            self.image.set_alpha(255 * (self.time_left / 5.0))
         if self.time_left < 0.0:
            self.end()
            return

class Onetime(Effect):
   def __init__(self, **args):
      Configurable.Configurable.__init__(self, locals())
      Effect.__init__(self, **args)
   
   def start(self, target):
      self.end()
   

class invulnerability(Effect):
   __slots__  = ('shield_color',)
   
   imagepath = 'InvincibilityIcon.bmp'

   def end(self):
      Effect.end(self)
      self.target.invulnerable = False
      if self.shield_color is not None and self.target.shield is not None:
         self.target.shield.color = self.shield_color
      G.game.HUD.healthcolor = HUD.healthcolor
      G.game.HUD.shieldcolor = HUD.shieldcolor
      G.game.HUD.refresh()

   def start(self, target):
      Effect.start(self, target)
      self.target.invulnerable = True
      self.shield_color = None
      if target.shield is not None:
         self.shield_color = self.target.shield.color
         self.target.shield.color = (255,160,160)
      G.game.HUD.healthcolor = HUD.invincibilitycolor
      G.game.HUD.shieldcolor = HUD.invincibilitycolor
      G.game.HUD.refresh()

class weapon_levelup(Onetime):
   def start(self, target):
      Onetime.start(self, target)
      if len(target.weapons) > 0:
         max_weapon = None
         for weapon in [w for w in target.weapons if w is not None]:
            if max_weapon is None or weapon.lattr('value') > max_weapon.lattr('value'):
               max_weapon = weapon
         if max_weapon is not None:
            max_weapon.level_up()

class ammo_refill(Onetime):
   __slots__ = ('amount',
                'proportion')
   
   def __init__(self, amount, proportion=None, **args):
      Configurable.Configurable.__init__(self, locals())
      Onetime.__init__(self, **args)

   def start(self, target):
      Onetime.start(self, target)
      if self.proportion is None:
         ammo_needs = list()
         for i, weapon in enumerate(target.weapons):
            if weapon is not None:
               max_ammo = weapon.lattr('max_ammo')
               if max_ammo > 0:
                  ammo_needs.append((i, max_ammo - weapon.ammo))
               else:
                  ammo_needs.append((i, 0))
            else:
               ammo_needs.append((i, 0))
         ammo_needs.sort(key=lambda x: x[1])
         optimal_refill = self.amount / len(ammo_needs)
         j = 0
         for i, ammoneed in ammo_needs:
            refill_amount = min(optimal_refill, ammoneed)
            if refill_amount > 0:
               target.weapons[i].ammo_refill(refill_amount)
               self.amount -= refill_amount
            j += 1
            if j < len(ammo_needs):
               optimal_refill = self.amount / (len(ammo_needs) - j)
      else:
         for weapon in target.weapons:
            if weapon is not None and weapon.lattr('max_ammo') > -1:
               weapon.ammo_refill(proportion=self.proportion)

class HP_refill(Onetime):
   __slots__ = ('amount',)
   
   def __init__(self, amount, **args):
      Configurable.Configurable.__init__(self, locals())
      Onetime.__init__(self, **args)

   def start(self, target):
      Onetime.start(self, target)
      target.heal(self.amount)

class money(Onetime):
   __slots__ = ('amount',)
   
   def __init__(self, amount, **args):
      Configurable.Configurable.__init__(self, locals())
      Onetime.__init__(self, **args)

   def start(self, target):
      Onetime.start(self, target)
      target.money += self.amount
      target.score += Config.moneytoscore * self.amount
